@page "/channelsconfiguration"
@rendermode InteractiveServer
@implements IDisposable
@using LiteDB
@using PHMEE.VibrationDataGenerator.Data
@using PHMEE.VibrationDataGenerator.Services
@inject ChannelConfigRepository ChannelConfigRepository
@inject WeiLiVibDataFilesService WeiLiVibDataFilesService

<PageTitle>ChannelsConfiguration</PageTitle>

<div>
    <h3 class="font-bold text-lg">Channels Config</h3>

    <div class="overflow-x-auto pt-4">
        <table class="table w-full">
            <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>DataSrcType</th>
                <th>Topic</th>
                <th>ChNo</th>
                <th>ChType</th>
                <th>Dir</th>
                <th>DaqChNumber</th>
                <th>Code</th>
                <th>Actions</th>
            </tr>
            </thead>
            <tbody>
            @foreach (var config in _channelConfigs)
            {
                <tr class="bg-base-200">
                    <td>@config.Id</td>
                    <td>@config.Name</td>
                    <td>@config.DataSrcType</td>
                    <td>@config.Topic</td>
                    <td>@config.ChNo</td>
                    <td>@config.ChType</td>
                    <td>@config.Dir</td>
                    <td>@config.DaqId</td>
                    <td>@config.DaqChNumber</td>
                    <td>@config.Code</td>
                    <td>
                        <button class="btn btn-outline btn-primary btn-sm" @onclick="() => EditConfig(config.Id)">Edit</button>
                        <button class="btn btn-outline btn-error btn-sm ml-2" @onclick="() => DeleteConfig(config.Id)">Delete</button>
                    </td>
                </tr>
            }
            </tbody>
        </table>
    </div>

    <div class="pt-4">
        <h4 class="font-bold text-md">@(_isEditMode ? "Edit Channel Configuration" : "Add New Channel Configuration")</h4>
        <div class="pt-4">
            <EditForm EditContext="_editContext" OnValidSubmit="SaveConfig" FormName="channelsconfiguration">
                <DataAnnotationsValidator/>
                <ValidationSummary/>

                <div class="form-control">
                    <label for="topic" class="label">Topic:</label>
                    <InputText id="topic" @bind-Value="_currentConfig.Topic" class="input input-bordered w-full max-w-xs"/>
                    <ValidationMessage For="@(() => _currentConfig.Topic)" class="text-error"/>
                </div>

                <div class="form-control">
                    <label for="name" class="label">Name:</label>
                    <InputText id="name" @bind-Value="_currentConfig.Name" class="input input-bordered w-full max-w-xs"/>
                    <ValidationMessage For="@(() => _currentConfig.Name)" class="text-error"/>
                </div>

                <div class="form-control">
                    <label for="dataSrcType" class="label">DataSrcType:</label>
                    <InputSelect id="dataSrcType" @bind-Value="SelectedDataSrcType" class="select select-bordered w-full max-w-xs">
                        @foreach (DataSrcType type in Enum.GetValues(typeof(DataSrcType)))
                        {
                            <option value="@((int)type)">@type</option>
                        }
                    </InputSelect>
                    <ValidationMessage For="@(() => _currentConfig.DataSrcType)" class="text-error"/>
                </div>

                <div class="form-control">
                    <label for="chNo" class="label">ChNo:</label>
                    <InputNumber id="chNo" @bind-Value="_currentConfig.ChNo" class="input input-bordered w-full max-w-xs"/>
                </div>

                <div class="form-control">
                    <label for="chType" class="label">ChType:</label>
                    <InputSelect id="chType" @bind-Value="_selectedChType" class="select select-bordered w-full max-w-xs">
                        @foreach (ChannelType type in Enum.GetValues(typeof(ChannelType)))
                        {
                            <option value="@((int)type)">@type</option>
                        }
                    </InputSelect>
                </div>


                <div class="form-control">
                    <label for="dir" class="label">Direction:</label>
                    <InputSelect id="dir" @bind-Value="_selectedDirection" class="select select-bordered w-full max-w-xs">
                        @foreach (SernorStyleEnum dir in Enum.GetValues(typeof(SernorStyleEnum)))
                        {
                            if (dir != SernorStyleEnum.D)
                            {
                                <option value="@((int)dir)">@dir</option>
                            }
                        }
                    </InputSelect>
                    <ValidationMessage For="@(() => _currentConfig.Dir)" class="text-error"/>
                </div>

                @if (_selectedDataSrcType == (int)DataSrcType.WeiLi)
                {
                    <div class="form-control">
                        <label for="daqId" class="label">DaqId:</label>
                        <InputSelect id="daqId" @bind-Value="_selectedDaqId" class="select select-bordered w-full max-w-xs">
                            @foreach (string daqId in _weiLiDaqIds)
                            {
                                <option value="@daqId">@daqId</option>
                            }
                        </InputSelect>
                        <ValidationMessage For="@(() => _currentConfig.DaqId)" class="text-error"/>
                    </div>

                    <div class="form-control">
                        <label for="daqChNumber" class="label">DaqChNumber:</label>
                        <InputSelect id="daqChNumber" @bind-Value="_selectedDaqChNumber" class="select select-bordered w-full max-w-xs">
                            @foreach (DaqChNumber daqChNumber in Enum.GetValues(typeof(DaqChNumber)))
                            {
                                if (daqChNumber != DaqChNumber.None)
                                {
                                    <option value="@((int)daqChNumber)">@daqChNumber</option>
                                }
                            }
                        </InputSelect>
                        <ValidationMessage For="@(() => _currentConfig.DaqChNumber)" class="text-error"/>
                    </div>
                }

                <div class="form-control">
                    <label for="code" class="label">Code:</label>
                    <InputSelect id="code" @bind-Value="_selectedIndicatorType" class="select select-bordered w-full max-w-xs">
                        @foreach (VibIndexEnum indicatorTypeCode in Enum.GetValues(typeof(VibIndexEnum)))
                        {
                            <option value="@((int)indicatorTypeCode)">@indicatorTypeCode</option>
                        }
                    </InputSelect>
                </div>

                <button type="submit" class="btn btn-primary mt-4">
                    @(_isEditMode ? "Update" : "Add")
                </button>
            </EditForm>
        </div>
    </div>
</div>

@code {
    private EditContext? _editContext;
    private ValidationMessageStore? _messageStore;

    private List<string> _weiLiDaqIds = [];

    private List<ChannelConfig> _channelConfigs = [];

    private ChannelConfig _currentConfig = new();

    private bool _isEditMode = false;

    private int _selectedChType;
    private int _selectedDirection;
    private int _selectedIndicatorType;
    private int _selectedDataSrcType;
    private int _selectedDaqChNumber;
    private string _selectedDaqId = string.Empty;
    private int SelectedDataSrcType
    {
        get => _selectedDataSrcType;
        set
        {
            _selectedDataSrcType = value;
            OnDataSrcTypeChanged(new ChangeEventArgs { Value = value });
        }
    }

    protected override void OnInitialized()
    {
        LoadConfigs();
        ResetForm();

        // 初始化 EditContext
        _editContext = new EditContext(_currentConfig);
        _editContext.OnValidationRequested += HandleValidationRequested;
        _messageStore = new ValidationMessageStore(_editContext);

        _weiLiDaqIds.AddRange(WeiLiVibDataFilesService.GetFolders());
    }

    private void LoadConfigs()
    {
        _channelConfigs = ChannelConfigRepository.GetAllConfigs();
    }

    private void SaveConfig()
    {
        _currentConfig.ChType = (ChannelType)_selectedChType;
        _currentConfig.Dir = (SernorStyleEnum)_selectedDirection;
        _currentConfig.Code = (VibIndexEnum)_selectedIndicatorType;
        _currentConfig.DataSrcType = (DataSrcType)_selectedDataSrcType;
        _currentConfig.DaqChNumber = (DaqChNumber)_selectedDaqChNumber;
        _currentConfig.DaqId = _selectedDaqId;

        if (_isEditMode)
        {
            ChannelConfigRepository.UpdateConfig(_currentConfig);
        }
        else
        {
            ChannelConfigRepository.AddConfig(_currentConfig);
        }

        LoadConfigs();
        ResetForm();
    }

    private void EditConfig(ObjectId id)
    {
        var config = ChannelConfigRepository.GetConfigById(id);

        _currentConfig = config;
        
        // 编辑时重新初始化 EditContext
        _editContext = new EditContext(_currentConfig);
        _editContext.OnValidationRequested += HandleValidationRequested;
        _messageStore = new ValidationMessageStore(_editContext);

        _selectedChType = (int)_currentConfig.ChType;
        _selectedDirection = (int)_currentConfig.Dir;
        _selectedIndicatorType = (int)_currentConfig.Code;
        _selectedDataSrcType = (int)_currentConfig.DataSrcType;
        _selectedDaqChNumber = (int)_currentConfig.DaqChNumber;
        _selectedDaqId = _currentConfig.DaqId;

        _isEditMode = true;
    }

    private void DeleteConfig(ObjectId id)
    {
        ChannelConfigRepository.DeleteConfig(id);
        LoadConfigs();
    }

    private void ResetForm()
    {
        _currentConfig = new ChannelConfig();
        _isEditMode = false;
        
        // ResetForm 时重新初始化 EditContext
        _editContext = new EditContext(_currentConfig);
        _editContext.OnValidationRequested += HandleValidationRequested;
        _messageStore = new ValidationMessageStore(_editContext);

        _selectedChType = 0;
        _selectedDirection = 0;
        _selectedIndicatorType = 0;
        _selectedDataSrcType = 0;
        _selectedDaqChNumber = 0;
        _selectedDaqId = string.Empty;
    }

    private void OnDataSrcTypeChanged(ChangeEventArgs args)
    {
        if (int.TryParse(args.Value?.ToString(), out int value))
        {
            _selectedDataSrcType = value;

            // 如果数据源切换为 JianLong，则清空 DaqId 和 DaqChNumber 
            if (_selectedDataSrcType == (int)DataSrcType.JianLong)
            {
                _selectedDaqId = string.Empty;
                _selectedDaqChNumber = (int)DaqChNumber.None;
            }
        }
    }

    private void HandleValidationRequested(object? sender, ValidationRequestedEventArgs eventArgs)
    {
        _messageStore?.Clear();

        // 自定义验证逻辑

        // 如果各个枚举类型的值存在不包含在枚举中的情况，则报错
        if (!Enum.IsDefined(typeof(DataSrcType), _selectedDataSrcType))
        {
            _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.DataSrcType)), "DataSrcType is not defined");
        }

        if (!Enum.IsDefined(typeof(SernorStyleEnum), _selectedDirection))
        {
            _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.Dir)), "Dir is not defined");
        }

        if (!Enum.IsDefined(typeof(VibIndexEnum), _selectedIndicatorType))
        {
            _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.Code)), "Code is not defined");
        }

        if (!Enum.IsDefined(typeof(ChannelType), _selectedChType))
        {
            _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.ChType)), "ChType is not defined");
        }

        if (!Enum.IsDefined(typeof(DaqChNumber), _selectedDaqChNumber))
        {
            _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.DaqChNumber)), "DaqChNumber is not defined");
        }

        // 数据源的逻辑校验
        if (_selectedDataSrcType == (int)DataSrcType.WeiLi)
        {
            // WeiLi 数据源的 DaqChNumber 不允许为 None
            if (_selectedDaqChNumber == (int)DaqChNumber.None)
            {
                _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.DaqChNumber)), "DataSrcType is WeiLi, but DaqChNumber is None");
            }

            // WeiLi 数据源的 DaqId 不允许为空
            if (string.IsNullOrWhiteSpace(_selectedDaqId))
            {
                _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.DaqId)), "DataSrcType is WeiLi, but DaqId is null");
            }
        }

        if (_selectedDataSrcType == (int)DataSrcType.JianLong)
        {
            // JianLong 数据源的 DaqId 必须为空
            if (!string.IsNullOrWhiteSpace(_selectedDaqId))
            {
                _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.DaqId)), "DataSrcType is JianLong, but DaqId is not null");
            }
            
            // JianLong 数据源的 DaqChNumber 必须为 None
            if (_selectedDaqChNumber != (int)DaqChNumber.None)
            {
                _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.DaqChNumber)), "DataSrcType is JianLong, but DaqChNumber is not None");
            }

            // JianLong 数据源的 Dir 不允许为 D
            if (_selectedDirection == (int)SernorStyleEnum.D)
            {
                _messageStore?.Add(new FieldIdentifier(_currentConfig, nameof(_currentConfig.Dir)), "DataSrcType is JianLong, but Dir is D");
            }
        }
    }

    public void Dispose()
    {
        if (_editContext is not null)
        {
            _editContext.OnValidationRequested -= HandleValidationRequested;
        }
    }

}